package at.fhooe.mcm.honeybadger.obd;

import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import at.fhooe.mcm.honeybadger.obd.commands.engine.EngineRPMObdCommand;
import at.fhooe.mcm.honeybadger.obd.enums.AvailableCommandNames;
import at.fhooe.mcm.honeybadger.obd.enums.FuelTrim;
import at.fhooe.mcm.honeybadger.obd.io.ObdCommandJob;
import at.fhooe.mcm.honeybadger.obd.io.ObdGatewayService;
import at.fhooe.mcm.honeybadger.obd.io.ObdGatewayServiceConnection;

public class MainActivity extends Activity {

	private static final String TAG = "OBDMainActivity";
	/*
	 * TODO put description
	 */
	static final int NO_BLUETOOTH_ID = 0;
	static final int BLUETOOTH_DISABLED = 1;
	static final int NO_GPS_ID = 2;
	static final int START_LIVE_DATA = 3;
	static final int STOP_LIVE_DATA = 4;
	static final int SETTINGS = 5;
	static final int COMMAND_ACTIVITY = 6;
	static final int TABLE_ROW_MARGIN = 7;
	static final int NO_ORIENTATION_SENSOR = 8;

	private Handler mHandler = new Handler();

	/**
	 * Callback for ObdGatewayService to update UI.
	 */
	private IPostListener mListener = null;
	private Intent mServiceIntent = null;
	private ObdGatewayServiceConnection mServiceConnection = null;

	private SensorManager sensorManager = null;
	private Sensor orientSensor = null;
	private SharedPreferences prefs = null;

	private PowerManager powerManager = null;
	private PowerManager.WakeLock wakeLock = null;

	private boolean preRequisites = true;

	private int speed = 1;
	private double maf = 1;
	private float ltft = 0;
	private double equivRatio = 1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mListener = new IPostListener() {
			public void stateUpdate(ObdCommandJob job) {
				String cmdName = job.getCommand().getName();
				String cmdResult = job.getCommand().getFormattedResult();

				Log.d(TAG, FuelTrim.LONG_TERM_BANK_1.getBank() + " equals "
						+ cmdName + "?");

				if (AvailableCommandNames.ENGINE_RPM.getValue().equals(cmdName)) {
					// TextView tvRpm = (TextView) findViewById(R.id.rpm_text);
					// tvRpm.setText(cmdResult);
					Log.d(TAG, "Engine RPM received: " + cmdResult);
				}
			}
		};

		final BluetoothAdapter mBtAdapter = BluetoothAdapter
				.getDefaultAdapter();
		if (mBtAdapter == null) {
			preRequisites = false;
			showDialog(NO_BLUETOOTH_ID);
		} else {
			// Bluetooth device is enabled?
			if (!mBtAdapter.isEnabled()) {
				preRequisites = false;
				showDialog(BLUETOOTH_DISABLED);
			}
		}

		// validate app pre-requisites
		if (preRequisites) {
			/*
			 * Prepare service and its connection
			 */
			mServiceIntent = new Intent(this, ObdGatewayService.class);
			mServiceConnection = new ObdGatewayServiceConnection();
			mServiceConnection.setServiceListener(mListener);

			// bind service
			Log.d(TAG, "Binding service..");
			bindService(mServiceIntent, mServiceConnection,
					Context.BIND_AUTO_CREATE);
		}
	}
	

	@Override
	protected void onDestroy() {
		super.onDestroy();

		releaseWakeLockIfHeld();
		mServiceIntent = null;
		mServiceConnection = null;
		mListener = null;
		mHandler = null;

	}

	@Override
	protected void onPause() {
		super.onPause();
		Log.d(TAG, "Pausing..");
		releaseWakeLockIfHeld();
	}

	/**
	 * If lock is held, release. Lock will be held when the service is running.
	 */
	private void releaseWakeLockIfHeld() {
		if (wakeLock.isHeld()) {
			wakeLock.release();
		}
	}

	protected void onResume() {
		super.onResume();

		Log.d(TAG, "Resuming..");

		prefs = PreferenceManager.getDefaultSharedPreferences(this);
		powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
		wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
				"ObdReader");
	}

	private void updateConfig() {
		Intent configIntent = new Intent(this, ConfigActivity.class);
		startActivity(configIntent);
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		menu.add(0, START_LIVE_DATA, 0, "Start Live Data");
		//menu.add(0, COMMAND_ACTIVITY, 0, "Run Command");
		menu.add(0, STOP_LIVE_DATA, 0, "Stop");
		menu.add(0, SETTINGS, 0, "Settings");
		return true;
	}
	
	public boolean onOptionsItemSelected(MenuItem item) {
		Log.d("LRI", "in onoptionsitemselected");
		
		switch (item.getItemId()) {
		case START_LIVE_DATA:
			startLiveData();
			return true;
		case STOP_LIVE_DATA:
			stopLiveData();
			return true;
		case SETTINGS:
			updateConfig();
			return true;
			// case COMMAND_ACTIVITY:
			// staticCommand();
			// return true;
		}
		return false;
	}
	
	private void startLiveData() {
		Log.d(TAG, "Starting live data..");
		
		
		String remoteDevice = prefs.getString(
		        ConfigActivity.BLUETOOTH_LIST_KEY, null);
		if (remoteDevice == null || "".equals(remoteDevice)) {
			Toast.makeText(this, "No Bluetooth device selected",
			        Toast.LENGTH_LONG).show();

			// log error
			Log.e(TAG, "No Bluetooth device has been selected.");
			
			return;
		}
		
		if (!mServiceConnection.isRunning()) {
			Log.d(TAG, "Service is not running. Going to start it..");
			startService(mServiceIntent);
			
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		Context context = getApplicationContext();
		CharSequence text = "Starting live data!";
		int duration = Toast.LENGTH_LONG;

		Toast toast = Toast.makeText(context, text, duration);
		toast.show();
		
		// start command execution
		mHandler.post(mQueueCommands);

		// screen won't turn off until wakeLock.release()
		wakeLock.acquire();
	}
	
	protected Dialog onCreateDialog(int id) {
		AlertDialog.Builder build = new AlertDialog.Builder(this);
		switch (id) {
		case NO_BLUETOOTH_ID:
			build.setMessage("Sorry, your device doesn't support Bluetooth.");
			return build.create();
		case BLUETOOTH_DISABLED:
			build.setMessage("You have Bluetooth disabled. Please enable it!");
			return build.create();
		case NO_GPS_ID:
			build.setMessage("Sorry, your device doesn't support GPS.");
			return build.create();
		case NO_ORIENTATION_SENSOR:
			build.setMessage("Orientation sensor missing?");
			return build.create();
		}
		return null;
	}

	private void stopLiveData() {
		Log.d(TAG, "Stopping live data..");

		if (mServiceConnection.isRunning())
			stopService(mServiceIntent);

		// remove runnable
		mHandler.removeCallbacks(mQueueCommands);

		releaseWakeLockIfHeld();
	}
	
	public boolean onPrepareOptionsMenu(Menu menu) {
		MenuItem startItem = menu.findItem(START_LIVE_DATA);
		MenuItem stopItem = menu.findItem(STOP_LIVE_DATA);
		MenuItem settingsItem = menu.findItem(SETTINGS);
		//MenuItem commandItem = menu.findItem(COMMAND_ACTIVITY);

		// validate if preRequisites are satisfied.
		if (preRequisites) {
			if (mServiceConnection.isRunning()) {
				startItem.setEnabled(false);
				stopItem.setEnabled(true);
				settingsItem.setEnabled(false);
//				commandItem.setEnabled(false);
			} else {
				stopItem.setEnabled(false);
				startItem.setEnabled(true);
				settingsItem.setEnabled(true);
//				commandItem.setEnabled(false);
			}
		} else {
			startItem.setEnabled(false);
			stopItem.setEnabled(false);
			settingsItem.setEnabled(false);
//			commandItem.setEnabled(false);
		}

		return true;
	}
	
	private Runnable mQueueCommands = new Runnable() {
		public void run() {
//			/*
//			 * If values are not default, then we have values to calculate MPG
//			 */
//			Log.d(TAG, "SPD:" + speed + ", MAF:" + maf + ", LTFT:" + ltft);
//			if (speed > 1 && maf > 1 && ltft != 0) {
//				FuelEconomyWithMAFObdCommand fuelEconCmd = new FuelEconomyWithMAFObdCommand(
//						FuelType.DIESEL, speed, maf, ltft, false /* TODO */);
//				TextView tvMpg = (TextView) findViewById(R.id.fuel_econ_text);
//				String liters100km = String.format("%.2f", fuelEconCmd.getLitersPer100Km());
//				tvMpg.setText("" + liters100km);
//				Log.d(TAG, "FUELECON:" + liters100km);
//			}

			// run again in 2s
			mHandler.postDelayed(mQueueCommands, 2000);

			if (mServiceConnection.isRunning())
				queueCommands();
		}
	};
	
	private void queueCommands() {
//		final ObdCommandJob airTemp = new ObdCommandJob(
//				new AmbientAirTemperatureObdCommand());
//		final ObdCommandJob speed = new ObdCommandJob(new SpeedObdCommand());
//		final ObdCommandJob fuelEcon = new ObdCommandJob(
//				new FuelEconomyObdCommand());
		final ObdCommandJob rpm = new ObdCommandJob(new EngineRPMObdCommand());
//		final ObdCommandJob maf = new ObdCommandJob(new MassAirFlowObdCommand());
//		final ObdCommandJob fuelLevel = new ObdCommandJob(
//				new FuelLevelObdCommand());
//		final ObdCommandJob ltft1 = new ObdCommandJob(new FuelTrimObdCommand(
//				FuelTrim.LONG_TERM_BANK_1));
//		final ObdCommandJob ltft2 = new ObdCommandJob(new FuelTrimObdCommand(
//				FuelTrim.LONG_TERM_BANK_2));
//		final ObdCommandJob stft1 = new ObdCommandJob(new FuelTrimObdCommand(
//				FuelTrim.SHORT_TERM_BANK_1));
//		final ObdCommandJob stft2 = new ObdCommandJob(new FuelTrimObdCommand(
//				FuelTrim.SHORT_TERM_BANK_2));
//		final ObdCommandJob equiv = new ObdCommandJob(new CommandEquivRatioObdCommand());

		// mServiceConnection.addJobToQueue(airTemp);
//		mServiceConnection.addJobToQueue(speed);
		// mServiceConnection.addJobToQueue(fuelEcon);
		mServiceConnection.addJobToQueue(rpm);
//		mServiceConnection.addJobToQueue(maf);
//		mServiceConnection.addJobToQueue(fuelLevel);
////		mServiceConnection.addJobToQueue(equiv);
//		mServiceConnection.addJobToQueue(ltft1);
		// mServiceConnection.addJobToQueue(ltft2);
		// mServiceConnection.addJobToQueue(stft1);
		// mServiceConnection.addJobToQueue(stft2);
	}
}
